package org.example.study11;

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;

/**
 * ReentrantLock 基础用法
 * 展示三种不同的加锁方式及其适用场景
 */
public class ReentrantLockBasicDemo {

    public static void main(String[] args) {
        // 创建ReentrantLock实例，默认是非公平锁
        // 非公平锁：线程获取锁的顺序不严格按照请求顺序，可能允许后来的线程插队
        // 优点：吞吐量通常高于公平锁
        ReentrantLock lock = new ReentrantLock();

        // 基础阻塞式加锁
        demonstrateBasicLocking(lock);

        // 非阻塞尝试加锁
        demonstrateTryLock(lock);

        // 带超时的尝试加锁
        demonstrateTimedTryLock(lock);
    }

    /**
     * 基础阻塞式加锁方式
     * 适用场景：必须获取锁才能继续执行的业务逻辑
     */
    private static void demonstrateBasicLocking(ReentrantLock lock) {
        System.out.println("=== 基础阻塞式加锁 ===");

        lock.lock(); // 获取锁，如果锁被其他线程持有则阻塞等待
        try {
            // 临界区代码 - 需要同步保护的代码块
            // 这里放置需要线程安全的业务逻辑
            System.out.println("线程 " + Thread.currentThread().getName() + " 成功获取锁");

            // 模拟业务处理
            Thread.sleep(500);

        } catch (InterruptedException e) {
            // 处理中断异常
            System.out.println("线程被中断");
            Thread.currentThread().interrupt(); // 恢复中断状态
        } finally {
            lock.unlock();  // 必须在finally块中释放锁，确保异常情况下锁也能被释放
            System.out.println("线程 " + Thread.currentThread().getName() + " 释放锁");
        }
    }

    /**
     * 非阻塞尝试加锁
     * 适用场景：快速失败，避免线程阻塞
     */
    private static void demonstrateTryLock(ReentrantLock lock) {
        System.out.println("\n=== 非阻塞尝试加锁 ===");

        boolean acquired = lock.tryLock();  // 立即尝试获取锁，不阻塞线程
        if (acquired) {
            try {
                System.out.println("尝试加锁成功，执行关键业务逻辑");
                // 成功获取锁后的业务逻辑
                // 这里放置需要在锁保护下执行的代码
            } finally {
                lock.unlock();  // 释放锁
                System.out.println("释放非阻塞尝试获取的锁");
            }
        } else {
            System.out.println("尝试加锁失败，锁已被其他线程持有");
            // 加锁失败后的备选方案
            // 例如：返回错误信息、使用备用逻辑、重试等
        }
    }

    /**
     * 带超时的尝试加锁
     * 适用场景：避免无限期等待，平衡响应时间和成功率
     */
    private static void demonstrateTimedTryLock(ReentrantLock lock) {
        System.out.println("\n=== 带超时的尝试加锁 ===");

        try {
            // 尝试在1秒内获取锁
            boolean timedAcquired = lock.tryLock(1, TimeUnit.SECONDS);
            if (timedAcquired) {
                try {
                    System.out.println("在超时时间内成功获取锁");
                    // 成功获取锁后的业务逻辑
                    Thread.sleep(300); // 模拟业务处理
                } finally {
                    lock.unlock();
                    System.out.println("释放超时尝试获取的锁");
                }
            } else {
                System.out.println("在指定超时时间内未能获取锁");
                // 超时后的处理逻辑
                // 例如：记录日志、返回超时错误、使用降级方案等
            }
        } catch (InterruptedException e) {
            System.out.println("尝试获取锁时线程被中断");
            Thread.currentThread().interrupt(); // 恢复中断状态
        }
    }
}